<template>
  <div ref="editorContainer" class="monaco-editor-container"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'

interface Props {
  modelValue: string
  language?: string
  theme?: string
  readOnly?: boolean
}

interface Emits {
  (e: 'update:modelValue', value: string): void
  (e: 'change', value: string): void
}

const props = withDefaults(defineProps<Props>(), {
  language: 'shell',
  theme: 'vs-dark',
  readOnly: false,
})

const emit = defineEmits<Emits>()
const editorContainer = ref<HTMLElement>()
let editor: monaco.editor.IStandaloneCodeEditor | null = null

// 配置 Monaco Editor 的 workers
self.MonacoEnvironment = {
  getWorker(_, label) {
    switch (label) {
      case 'json':
        return new jsonWorker()
      case 'css':
      case 'scss':
      case 'less':
        return new cssWorker()
      case 'html':
      case 'handlebars':
      case 'razor':
        return new htmlWorker()
      case 'typescript':
      case 'javascript':
        return new tsWorker()
      default:
        return new editorWorker()
    }
  },
}

// 初始化编辑器
const initEditor = async () => {
  if (!editorContainer.value) return

  try {
    // 注册语言建议
    registerLanguageSuggestions()

    // 配置编辑器选项
    editor = monaco.editor.create(editorContainer.value, {
      value: props.modelValue,
      language: props.language,
      theme: props.theme,
      readOnly: props.readOnly,
      automaticLayout: true,
      minimap: { enabled: true },
      scrollBeyondLastLine: false,
      lineNumbers: 'on',
      renderLineHighlight: 'all',
      matchBrackets: 'always',
      autoClosingBrackets: 'always',
      formatOnPaste: true,
      formatOnType: true,
      tabSize: 2,
      fontSize: 14,
      fontFamily: "'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', monospace",
      suggest: {
        showWords: true,
        snippetsPreventQuickSuggestions: false,
      },
      renderWhitespace: 'none',
      folding: true,
      wordWrap: 'on',
    })

    // 监听内容变化
    editor.onDidChangeModelContent(() => {
      const value = editor?.getValue() ?? ''
      emit('update:modelValue', value)
      emit('change', value)
    })
  } catch (err) {
    console.error('Monaco Editor 初始化失败:', err)
  }
}

// 注册语言建议
const registerLanguageSuggestions = () => {
  // Shell 语言建议
  monaco.languages.registerCompletionItemProvider('shell', {
    provideCompletionItems: () => {
      const suggestions = [
        {
          label: 'if',
          kind: monaco.languages.CompletionItemKind.Snippet,
          insertText: 'if [[ ${1:condition} ]]; then\n\t${2}\nfi',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'If statement',
        },
        {
          label: 'for',
          kind: monaco.languages.CompletionItemKind.Snippet,
          insertText: 'for ${1:var} in ${2:list}; do\n\t${3}\ndone',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'For loop',
        },
        {
          label: 'while',
          kind: monaco.languages.CompletionItemKind.Snippet,
          insertText: 'while [[ ${1:condition} ]]; do\n\t${2}\ndone',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'While loop',
        },
        // 添加更多 shell 命令和片段...
      ]
      return { suggestions }
    },
  })

  // Python 语言建议
  monaco.languages.registerCompletionItemProvider('python', {
    provideCompletionItems: () => {
      const suggestions = [
        {
          label: 'def',
          kind: monaco.languages.CompletionItemKind.Snippet,
          insertText: 'def ${1:function_name}(${2:parameters}):\n\t${3:pass}',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Function definition',
        },
        {
          label: 'class',
          kind: monaco.languages.CompletionItemKind.Snippet,
          insertText: 'class ${1:ClassName}:\n\tdef __init__(self):\n\t\t${2:pass}',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Class definition',
        },
        // 添加更多 Python 建议...
      ]
      return { suggestions }
    },
  })

  // JavaScript 语言建议
  monaco.languages.registerCompletionItemProvider('javascript', {
    provideCompletionItems: () => {
      const suggestions = [
        {
          label: 'function',
          kind: monaco.languages.CompletionItemKind.Snippet,
          insertText: 'function ${1:name}(${2:params}) {\n\t${3}\n}',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Function declaration',
        },
        {
          label: 'class',
          kind: monaco.languages.CompletionItemKind.Snippet,
          insertText: 'class ${1:Name} {\n\tconstructor(${2:params}) {\n\t\t${3}\n\t}\n}',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Class declaration',
        },
        // 添加更多 JavaScript 建议...
      ]
      return { suggestions }
    },
  })
}

// 监听语言变化
watch(
  () => props.language,
  (newLanguage) => {
    if (editor) {
      const model = editor.getModel()
      if (model) {
        monaco.editor.setModelLanguage(model, newLanguage)
      }
    }
  },
)

// 监听值变化
watch(
  () => props.modelValue,
  (newValue) => {
    if (editor && newValue !== editor.getValue()) {
      editor.setValue(newValue)
    }
  },
)

// 格式化代码
const formatCode = () => {
  editor?.getAction('editor.action.formatDocument')?.run()
}

// 暴露方法给父组件
defineExpose({
  formatCode,
})

onMounted(() => {
  initEditor()
})

onBeforeUnmount(() => {
  editor?.dispose()
})
</script>

<style scoped>
.monaco-editor-container {
  width: 100%;
  height: 100%;
  min-height: 300px;
}
</style>
